package client;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.UnknownHostException;
import java.security.KeyStore;
import java.util.Properties;
import java.util.Scanner;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class ClientSocketConnection {
	private static final int ACCESS_GRANTED = 42;
	private static final int ACCESS_DENIED = 41;
	
	private static final int REQUEST_JOURNAL_LIST = 0;
	private static final int REQUEST_READ_FILE = 1;
	private static final int REQUEST_CREATE_FILE = 2;
	private static final int REQUEST_WRITE_FILE = 3;
	private static final int REQUEST_DELETE_FILE = 4;
	
	private static final String SERVER_END_OF_FILE = "EOF";
	
	private PrintWriter output;
	private BufferedReader input;
	
	private JournalReader journalReader;

	public ClientSocketConnection(String host, int port) {
		journalReader = new JournalReader(this);

		Properties systemProps = System.getProperties();
		systemProps.put("javax.net.ssl.trustStore", "../cert/ca/truststore");
		systemProps.put("javax.net.ssl.trustStorePassword", "password"); 
		System.setProperties(systemProps);

		SSLSocketFactory factory = null;
		try {
			SSLContext ctx;
			KeyManagerFactory kmf;
			KeyStore ks;

			ctx = SSLContext.getInstance("TLS");
			kmf = KeyManagerFactory.getInstance("SunX509");
			ks = KeyStore.getInstance("JKS");

			Scanner scan = new Scanner(System.in);
			
			System.out.println("Enter the name of your keystore file:");
			String keystoreFile = scan.nextLine();
			
			System.out.println("Enter the password to the keystore file:");
			String password = scan.nextLine();
			
			char[] passphrase = password.toCharArray();
			ks.load(new FileInputStream("../cert/keystores/" + keystoreFile), passphrase);

			kmf.init(ks, passphrase);
			ctx.init(kmf.getKeyManagers(), null, null);

			factory = ctx.getSocketFactory();
		} catch (Exception e) {
			e.printStackTrace();
		}

		SSLSocket socket;
		while (true) {
			try {
				socket = (SSLSocket) factory.createSocket(host, port);
				socket.startHandshake();


				output = new PrintWriter(socket.getOutputStream());
				input = new BufferedReader(new InputStreamReader(socket.getInputStream()));


				presentMenu();

			} catch (UnknownHostException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	private void presentMenu() {

		Scanner scan = new Scanner(System.in);
		
		int chosenOption = -1;
		String chosenJournal = null;
		while (chosenOption != 0) {
			output.write(REQUEST_JOURNAL_LIST);
			output.flush();
			
			String journalList = readAllIncomingTextFromServer();
			
			System.out.println("Choose from the following alternatives:");
			System.out.println("1. Read a journal\n2. Create a new journal\n3. Delete a journal\n0. Exit");
			chosenOption = scan.nextInt();
			scan.nextLine();
			
			System.out.println("Journals available on the server:");
			System.out.println(journalList);

			switch (chosenOption) {
			case 1:
				System.out.println("Select the journal that you want to read by entering the journal name:");
				chosenJournal = scan.nextLine();
				
				String journal = requestReadJournal(chosenJournal);
				
				if (journal != null) {
					journalReader.openJournal(chosenJournal, journal);
				}
					
				break;
			case 2:
				if (requestCreateJournal()) {
					System.out.println("Enter the name of the patient:");
					chosenJournal = scan.nextLine();
					
					System.out.println("Enter the name of the associated nurse:");
					String nurse = scan.nextLine();
					
					output.write(chosenJournal + "\n");
					output.write(nurse + "\n");
					output.write(SERVER_END_OF_FILE + "\n");
					output.flush();
					
					System.out.println("Journal has been created on the server");
				}
				
				
				break;
			case 3:
				System.out.println("Select the journal that you want to delete by entering the journal name");
				chosenJournal = scan.nextLine();
				
				requestDeleteJournal(chosenJournal);
				break;
			case 0:
				System.exit(0);
				break;
			}
		}
		
		scan.close();
	}

	public void requestDeleteJournal(String chosenJournal) {
		output.write(REQUEST_DELETE_FILE);
		output.flush();
		
		try {
			if (input.read() == ACCESS_DENIED) {
				System.out.println("Access denied: You do not have permission to delete a journal");
				return;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		output.write(chosenJournal + "\n");
		output.flush();
		System.out.println("Journal deleted on server");
	}

	public boolean requestCreateJournal() {
		output.write(REQUEST_CREATE_FILE);
		output.flush();
		
		try {
			if (input.read() == ACCESS_DENIED) {
				System.out.println("Access denied: You do not have permission to create a journal");
				return false;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return true;
	}

	public void requestWriteJournal(String chosenJournal, String contents) {
		output.write(REQUEST_WRITE_FILE);
		output.write(chosenJournal + "\n");
		output.flush();
		
		try {
			if (input.read() == ACCESS_DENIED) {
				System.out.println("Access denied: You do not have permission to write to this journal");
				return;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("File has been updated on the server");
		output.write(contents + "\n");
		output.write(SERVER_END_OF_FILE + "\n");
		output.flush();
	}
	
	public String requestReadJournal(String chosenJournal) {
		output.write(REQUEST_READ_FILE);
		output.write(chosenJournal + "\n");
		output.flush();
		
		try {
			if (input.read() == ACCESS_DENIED) {
				System.out.println("Access denied: You do not have permission to read this journal");
				return null;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return readAllIncomingTextFromServer();
	}

	private String readAllIncomingTextFromServer() {
		StringBuilder sb = new StringBuilder();

		try {
			String line = "";
			for (int i = 0; !(line = input.readLine()).equals(SERVER_END_OF_FILE); i++) {
				sb.append(line + "\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return sb.toString();
	}
}
